/**
 * 判断文件类型
 * @author ok-mini
 * FileTools v1.0
 */

class FileTools {
  static instance;
  //文件头信息参考文档：https://blog.csdn.net/ccj2020/article/details/87603903
  //文件头信息参考文档：https://blog.csdn.net/txgc0/article/details/17246625
  //文件头信息参考文档：https://www.cnblogs.com/yuluoxingkong/p/10675521.html

  /**
   * 文件头信息
   * 文件若存在多种头部信息，可使用数组
   * */
  static FILE_BOOL = {
    "PNG": '89 50 4E 47 0D 0A 1A 0A',
    "GIF": '47 49 46 38',
    "PDF": '25 50 44 46',
    "XLS_DOC": 'D0 CF 11 E0',
    "XLSX_DOCX": '50 4B 03 04 14 00 06 00 08 00 00 00 21 00',
    "ZIP": [
      '50 4B 03 04',
      '50 4B 05 06',
      '50 4B 07 08',
    ],
    "RAR": '52 61 72 21 1A 07 00',
    "7Z": '37 7A BC AF 27 1C',
    "BZ": '42 5A 68',
    "TAR": '1F 8B 08',
    "MP3": '49 44 33 03 00 00 00 00 21 76',
    "FLV": '46 4C 56 01 05 00 00 00 09 00',
    "MP4": '00 00 00 20 66 74 79 70 6D 70',
  };

  /**
   * 调用此静态方法实现单例
   * */
  static getInstance() {
    if (false === this.instance instanceof this) {
      this.instance = new this;
      // console.log("创建新对象");
    }
    return this.instance;
  }

  /**
   * 将File对象转成16进制
   * @param file <File|Blob>
   * @returns {Promise<string>}
   * @private
   */
  _hexdump(file) {
    return new Promise(resolve => {
      const fr = new FileReader();
      fr.readAsArrayBuffer(file);
      fr.addEventListener("loadend", (e) => {
        const res = e.target.result;
        let tempStr = [];
        (new Uint8Array(res)).forEach(item => {
          let temp = (item.toString(16)).toLocaleUpperCase();
          temp = temp.length < 2 ? 0 + temp : temp;
          tempStr.push(temp);
        });
        resolve(tempStr.join(" "));
      }, false);
    });

    /*return new Promise(resolve => {
      blob.arrayBuffer().then(res => {
        let tempStr = [];
        (new Uint8Array(res)).forEach(item => {
          let temp = (item.toString(16)).toLocaleUpperCase();
          temp = temp.length < 2 ? 0 + temp : temp;
          tempStr.push(temp);
        });
        resolve(tempStr.join(" "));
      }).catch(err => {
        resolve("");
      });
    });*/
  }

  /**
   * 去掉字符串中所有的空格
   * @param str
   * @returns {string}
   * @private
   */
  _trimAll(str) {
    if (str === undefined || str === null) {
      str = str || "";
    }
    str += "";
    return str.replace(/(\s*)/g, "");
  }

  /**判断值类型*/
  _typeOf(obj) {
    let type_of = typeof obj;
    type_of = type_of.toLocaleLowerCase();
    if ("object" === type_of) {
      let call = Object.prototype.toString.call(obj);
      call = (call.toLocaleLowerCase()).substring(8, call.length - 1);
      return call;
    } else {
      return type_of;
    }
  }

  /**
   * 图片信息(宽高，大小等)
   * @param blob Blob
   * @private
   */
  imgInfo(blob) {
    let image = new Image();
    image.src = blob;
    image.onload = function () {
      console.log("width:" + image.width);
      console.log("height:" + image.height);
    }
  }

  /**
   * 判断文件 类型
   * @param file File
   * @param key String
   * @returns {Promise<boolean>}
   */
  async isFile(file, key) {
    const hex = FileTools.FILE_BOOL[key];
    let len = 0;
    if (this._typeOf(hex) === "array") {
      for (let i = 0; i < hex.length; i++) {
        len = parseInt((this._trimAll(hex[i]).length / 2) + "");
        let fileHex = await this._hexdump(file.slice(0, len));
        if (hex[i] === fileHex) {
          return true;
        }
      }
      return false;
    } else {
      len = parseInt((this._trimAll(hex).length / 2) + "");
      let fileHex = await this._hexdump(file.slice(0, len));
      return hex === fileHex;
    }
  }

  /**
   * 判断文件是否是JPG文件
   * @param file File
   * @returns {Promise<boolean>}
   */
  async isJPG(file) {
    let len = file.size;
    let start = await this._hexdump(file.slice(0, 2));//FF D8
    let end = await this._hexdump(file.slice(-2, len));//FF D9

    return start === "FF D8" && end === "FF D9";
  }

  /**
   * 判断文件是否是PNG文件
   * @param file File
   * @returns {Promise<boolean>}
   */
  async isPNG(file) {
    return this.isFile(file, 'PNG');
  }

  /**
   * 判断文件是否是GIF文件
   * @param file File
   * @returns {Promise<boolean>}
   */
  async isGIF(file) {
    return this.isFile(file, 'GIF');
  }

  /**
   * 判断文件是否是PDF文件
   * @param file File
   * @returns {Promise<boolean>}
   */
  async isPDF(file) {
    return this.isFile(file, 'PDF');
  }

  /**
   * 判断文件是否是zip文件
   * @param file File
   * @returns {Promise<boolean>}
   */
  async isZIP(file) {
    return this.isFile(file, 'ZIP');
  }

  /**
   * 判断文件是否是7z文件
   * @param file File
   * @returns {Promise<boolean>}
   */
  async is7Z(file) {
    return this.isFile(file, '7Z');
  }

  /**
   * 判断文件是否是rar文件
   * @param file File
   * @returns {Promise<boolean>}
   */
  async isRAR(file) {
    return this.isFile(file, 'RAR');
  }

  /**
   * 判断是否是图片 '.png', '.jpg', '.jpeg', '.gif'
   * @param file
   * @returns {Promise<boolean>}
   */
  async isImg(file) {
    const _suffix = (file.name.substring(file.name.lastIndexOf('.'))).toLowerCase();
    switch (_suffix) {
      case '.png':
        return this.isPNG(file);
      case '.gif':
        return this.isGIF(file);
      default:
        if (_suffix === '.jpg' || _suffix === '.jpeg') {
          return this.isJPG(file);
        } else {
          return false;
        }
    }
  }

  /**
   * 判断文件是否是压缩文件 '.zip', '.7z', '.rar'
   * @param file File
   * @returns {Promise<boolean>}
   */
  async isArchive(file) {
    const _suffix = (file.name.substring(file.name.lastIndexOf('.'))).toLowerCase();
    switch (_suffix) {
      case '.zip':
        return this.isZIP(file);
      case '.7z':
        return this.is7Z(file);
      case '.rar':
        return this.isRAR(file);
      default:
        return false;
    }
  }

}

export default FileTools.getInstance();
